


#include "udp_socket.h"



#define UDP_LOG_DOMAN       "udp-socket"
#define udp_debug(...)  	qelog_debug(UDP_LOG_DOMAN, __VA_ARGS__)
#define udp_info(...)   	qelog_info(UDP_LOG_DOMAN, __VA_ARGS__)
#define udp_notice(...) 	qelog_notice(UDP_LOG_DOMAN, __VA_ARGS__)
#define udp_warning(...)    qelog_warning(UDP_LOG_DOMAN, __VA_ARGS__)
#define udp_critical(...)   qelog_critical(UDP_LOG_DOMAN, __VA_ARGS__)
#define udp_error(...)  	qelog_error(UDP_LOG_DOMAN, __VA_ARGS__)
#define udp_fatal(...)		qelog_fatal(UDP_LOG_DOMAN, __VA_ARGS__)
#define udp_hexdump(...)    qehex_debug(UDP_LOG_DOMAN, __VA_ARGS__)



qe_ret udp_socket_init(udp_socket *sock)
{
    WSAStartup(MAKEWORD(2, 2), &sock->ws);

    sock->s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (!sock->s) {
        udp_error("socket create error");
        return qe_err_common;
    }
    
    return qe_ok;
}

qe_ret udp_socket_group_add(udp_socket *sock, const char *address)
{
    BOOL reuse = TRUE;
    struct ip_mreq mreq;

    mreq.imr_multiaddr.s_addr = inet_addr(address);
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);

    if (setsockopt(sock->s, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) == SOCKET_ERROR) {
        udp_error("setsockopt(SO_REUSEADDR) failed: %d", WSAGetLastError());
        closesocket(sock->s);
        WSACleanup();
        return qe_err_common;
    }

    if (setsockopt(sock->s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq)) == SOCKET_ERROR) {
        udp_error("setsockopt(IP_ADD_MEMBERSHIP) failed: %d", WSAGetLastError());
        closesocket(sock->s);
        WSACleanup();
        return qe_err_common;
    }

    return qe_ok;
}

qe_ret udp_socket_set_timeout(udp_socket *sock, qe_uint timeout_ms)
{
    int ret;
    DWORD val = timeout_ms;

    ret = setsockopt(sock->s, SOL_SOCKET, SO_RCVTIMEO, (const char*)&val, sizeof(val));
    if (ret < 0) {
        udp_error("set timeout error");
        return qe_err_param;
    }

    return qe_ok;
}

qe_ret udp_socket_bind(udp_socket *sock, SOCKADDR_IN *addr)
{
    int r;

    r = bind(sock->s, (struct sockaddr *)addr, sizeof(*addr));
    if (r < 0) {
        udp_error("socket bind error");
        return qe_err_common;
    }

    return qe_ok;
}

qe_int udp_socket_send(udp_socket *sock, char *buf, int size, SOCKADDR_IN *dst)
{
    int n;

    n = sendto(sock->s, buf, size, 0,
            (struct sockaddr *)dst,
            sizeof(*dst));
    if (n < 0) {
        udp_error("send error");
        return n;
    }

    if (n != size) {
        udp_warning("send size error, %d %d", n, size);
    }

    return n;
}

qe_int udp_socket_recv(udp_socket *sock, char *buf, int size, SOCKADDR_IN *src)
{
    int n;
    int addrlen;

    n = recvfrom(sock->s, buf, size, 0,
            (struct sockaddr *)src,
            &addrlen);
    if (n < 0) {
        return -(qe_err_common);
    }

    return n;
}

void udp_socket_exit(udp_socket *sock)
{
    if (sock->s) {
        closesocket(sock->s);
        WSACleanup();
        udp_debug("udp socket exit");
    }
}